bitkeeper revision 1.259.1.1 (3f045a1aTKC1vRJU2nif7VHOWTRJ1g)
authorsos22@labyrinth.cl.cam.ac.uk <sos22@labyrinth.cl.cam.ac.uk>
Thu, 3 Jul 2003 16:30:18 +0000 (16:30 +0000)
committersos22@labyrinth.cl.cam.ac.uk <sos22@labyrinth.cl.cam.ac.uk>
Thu, 3 Jul 2003 16:30:18 +0000 (16:30 +0000)
New physical disk access control stuff.

16 files changed:
.rootkeys
tools/internal/Makefile
tools/internal/physdev.h [new file with mode: 0644]
tools/internal/xi_phys_grant.c [new file with mode: 0644]
tools/internal/xi_phys_probe.c [new file with mode: 0644]
tools/internal/xi_phys_revoke.c [new file with mode: 0644]
xen/common/domain.c
xen/drivers/block/xen_block.c
xen/drivers/block/xen_physdisk.c [new file with mode: 0644]
xen/include/hypervisor-ifs/block.h
xen/include/xeno/sched.h
xenolinux-2.4.21-sparse/arch/xeno/drivers/block/Makefile
xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c
xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c [new file with mode: 0644]
xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ [new file with mode: 0644]
xenolinux-2.4.21-sparse/drivers/block/ll_rw_blk.c

index 5e185dc23760f7399609c0c9b40a14a32a55e0e5..9f86143bbf2d7ebfd8a721e884b2773cc9e86200 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ee609b3Yr4aggmLSKmhiIzT8-nURA tools/internal/dom0_ops.h
 3eb781fddjylXbsepjppUyIXa5lcaQ tools/internal/hypervisor_defs.h
 3eb781fdKiQbgozBsgs_zzJQ9ubehw tools/internal/mem_defs.h
+3f04589dFbtsbWWwAXq3I92UiAogCg tools/internal/physdev.h
 3ec61e1bJCeJJu0SsptmDpA1xKvwvw tools/internal/rpm.spec
 3eb781fdgbSkh2O6JQS-65Dz4n0ItQ tools/internal/xi_build.c
 3eb781fdW1SAyiaC4mTsXq_9fRHh-A tools/internal/xi_create.c
 3eb781fdcJ0fF7rWfzAOArW-x4-gwA tools/internal/xi_destroy.c
 3ec43c5dmQxGDvgJJXbV1yLxT30Y1A tools/internal/xi_helper
 3eb83c3bZeECmphOKOJxSu4Lo1LpBw tools/internal/xi_list
+3f0458aaXhD8BQAggO81gv30RQ-ifA tools/internal/xi_phys_grant.c
+3f0458aaJHmlzkDwf0qxEzAcjX55sg tools/internal/xi_phys_probe.c
+3f0458aaVAbFSwptQbQAnDOiZlwQ3w tools/internal/xi_phys_revoke.c
 3eb781fd8oRfPgH7qTh7xvgmwD6NgA tools/internal/xi_start.c
 3eb781fd0Eo9K1jEFCSAVzO51i_ngg tools/internal/xi_stop.c
 3eb781fd7211MZsLxJSiuy7W4KnJXg tools/internal/xi_vifinit
 3ddb79beNQVrdGyoI4njXhgAjD6a4A xen/drivers/block/genhd.c
 3ddb79beyWwLRP_BiM2t1JKgr_plEw xen/drivers/block/ll_rw_blk.c
 3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen/drivers/block/xen_block.c
+3f045882spujO81dMl-fYWGiZ8WcPw xen/drivers/block/xen_physdisk.c
 3e5d129asHNyZOjBKTkqs-9AFzxemA xen/drivers/block/xen_segment.c
 3e9c248afxxsnAzIt2na7Ej24yNFzg xen/drivers/cdrom/Makefile
 3e9c248ajUkn2W3n4vgm72Hp2ftZ8A xen/drivers/cdrom/cdrom.c
 3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.c
 3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_block.h
 3e677190SjkzJIvFifRVeYpIZOCtYA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_ide.c
+3f045897EIYU5l5jxFBpeF1Z0ZOTwA xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c
+3f045a16wW57GFQ3r3Ta2cJOo1ierQ xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~
 3e677193nOKKTLJzcAu4SYdbZaia8g xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_scsi.c
 3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_segment.c
 3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_segment_proc.c
index 417ffe7adbb5dbffe026324cc746272ab6b3d5f2..8b50b410e83b3060221b0afe0cf1935850d47539 100644 (file)
@@ -4,13 +4,18 @@ XI_START = xi_start
 XI_STOP = xi_stop
 XI_DESTROY = xi_destroy
 XI_BUILD = xi_build
+XI_PHYS_GRANT = xi_phys_grant
+XI_PHYS_REVOKE = xi_phys_revoke
 
-all: $(XI_CREATE).o $(XI_START).o $(XI_STOP).o $(XI_DESTROY).o $(XI_BUILD).o
+all: $(XI_CREATE).o $(XI_START).o $(XI_STOP).o $(XI_DESTROY).o $(XI_BUILD).o \
+       $(XI_PHYS_GRANT).o $(XI_PHYS_REVOKE).o
        $(CC) -o $(XI_CREATE) $(XI_CREATE).o
        $(CC) -o $(XI_BUILD) $(XI_BUILD).o
        $(CC) -o $(XI_START) $(XI_START).o
        $(CC) -o $(XI_STOP) $(XI_STOP).o
        $(CC) -o $(XI_DESTROY) $(XI_DESTROY).o
+       $(CC) -o $(XI_PHYS_GRANT) $(XI_PHYS_GRANT).o
+       $(CC) -o $(XI_PHYS_REVOKE) $(XI_PHYS_REVOKE).o
 
 $(XI_CREATE).o: $(XI_CREATE).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h
        $(CC) -c $(XI_CREATE).c 
@@ -27,8 +32,14 @@ $(XI_STOP).o: $(XI_STOP).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h
 $(XI_DESTROY).o: $(XI_DESTROY).c dom0_ops.h dom0_defs.h
        $(CC) -c $(XI_DESTROY).c 
 
+$(XI_PHYS_GRANT).o: $(XI_PHYS_GRANT).c physdev.h
+       $(CC) -c $(XI_PHYS_GRANT).c 
+
+$(XI_PHYS_REVOKE).o: $(XI_PHYS_REVOKE).c physdev.h
+       $(CC) -c $(XI_PHYS_REVOKE).c 
+
 install: all
-       cp -a xi_list xi_vifinit xi_helper $(XI_CREATE) $(XI_BUILD) $(XI_START) $(XI_STOP) $(XI_DESTROY) ../../../install/bin
+       cp -a xi_list xi_vifinit xi_helper $(XI_CREATE) $(XI_BUILD) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_PHYSDEV_GRANT) $(XI_PHYS_REVOKE) ../../../install/bin
        chmod 755 ../../../install/bin/xi_list
        chmod 755 ../../../install/bin/xi_vifinit
        chmod 755 ../../../install/bin/xi_helper
@@ -42,5 +53,5 @@ rpm: all
        rm -rf staging
 
 clean:
-       $(RM) *.o *.rpm $(XI_CREATE) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_BUILD)
+       $(RM) *.o *.rpm $(XI_CREATE) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_BUILD) $(XI_PHYSDEV_GRANT)
 
diff --git a/tools/internal/physdev.h b/tools/internal/physdev.h
new file mode 100644 (file)
index 0000000..54a0120
--- /dev/null
@@ -0,0 +1,26 @@
+#define XEN_BLOCK_PHYSDEV_GRANT 10 /* grant access to range of disk blocks */
+#define XEN_BLOCK_PHYSDEV_REVOKE 11 /* revoke access to range of disk blocks */
+#define XEN_BLOCK_PHYSDEV_PROBE 12 /* probe for a domain's physdev
+                                     accesses */
+
+typedef struct xp_disk
+{
+  int mode;
+  int domain;
+  unsigned short device;
+  unsigned long start_sect;
+  unsigned long n_sectors;
+} xp_disk_t;
+
+#define PHYSDISK_MAX_ACES_PER_REQUEST 254
+typedef struct {
+  int n_aces;
+  int domain;
+  int start_ind;
+  struct {
+    unsigned short device;
+    unsigned long start_sect;
+    unsigned long n_sectors;
+    unsigned mode;
+  } entries[PHYSDISK_MAX_ACES_PER_REQUEST];
+} physdisk_probebuf_t;
diff --git a/tools/internal/xi_phys_grant.c b/tools/internal/xi_phys_grant.c
new file mode 100644 (file)
index 0000000..7912185
--- /dev/null
@@ -0,0 +1,43 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+
+#include "physdev.h"
+
+int main(int argc, char *argv[])
+{
+  xp_disk_t buf;
+  int fd;
+
+  if (argc != 6) {
+    fprintf(stderr, "Usage: xi_physdev_grant <r/rw> <domain> <device> <start sector> <n_sectors>\n");
+    return 1;
+  }
+
+  buf.mode = 0;
+  if (argv[1][0] == 'r')
+    buf.mode |= 1;
+  else if (argv[1][0] == 'w')
+    buf.mode |= 2;
+  if (argv[1][1] == 'r')
+    buf.mode |= 1;
+  else if (argv[1][1] == 'w')
+    buf.mode |= 2;
+  
+  buf.domain = atol(argv[2]);
+  buf.device = atol(argv[3]);
+  buf.start_sect = atol(argv[4]);
+  buf.n_sectors = atol(argv[5]);
+
+  fd = open("/proc/xeno/dom0/phd", O_WRONLY);
+  if (fd < 0) {
+    fprintf(stderr, "Can\'t open /proc/xeno/dom0/phd: %s.\n", strerror(errno));
+    return 1;
+  }
+
+  write(fd, &buf, sizeof(buf));
+  close(fd);
+
+  return 0;
+}
diff --git a/tools/internal/xi_phys_probe.c b/tools/internal/xi_phys_probe.c
new file mode 100644 (file)
index 0000000..caa01d3
--- /dev/null
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "physdev.h"
+
+int main(int argc, char *argv[])
+{
+  physdisk_probebuf_t buf;
+  int fd;
+  int x;
+
+  if (argc != 2) {
+    fprintf(stderr, "Usage: xi_phys_probe <domain_nr>\n");
+    return 1;
+  }
+
+  fd = open("/proc/xeno/dom0/phd", O_RDONLY);
+  if (fd < 0) {
+    fprintf(stderr, "Can\'t open /proc/xeno/dom0/phd: %s.\n",
+           strerror(errno));
+    return 1;
+  }
+
+  memset(&buf, 0, sizeof(buf));
+  buf.n_aces = PHYSDISK_MAX_ACES_PER_REQUEST;
+  while (buf.n_aces == PHYSDISK_MAX_ACES_PER_REQUEST ||
+        buf.n_aces == 0) {
+    buf.n_aces = PHYSDISK_MAX_ACES_PER_REQUEST;
+    buf.domain = atol(argv[1]);
+    read(fd, &buf, sizeof(buf));
+    if (!buf.n_aces)
+      break;
+
+    printf("Found %d ACEs\n", buf.n_aces);
+
+    for (x = 0; x < buf.n_aces; x++) {
+      printf("%x:[%x,%x) : %x\n", buf.entries[x].device,
+            buf.entries[x].start_sect,
+            buf.entries[x].start_sect  + buf.entries[x].n_sectors,
+            buf.entries[x].mode);
+    }
+    buf.start_ind += buf.n_aces;
+  }
+  return 0;
+}
diff --git a/tools/internal/xi_phys_revoke.c b/tools/internal/xi_phys_revoke.c
new file mode 100644 (file)
index 0000000..b4bf728
--- /dev/null
@@ -0,0 +1,33 @@
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/fcntl.h>
+
+#include "physdev.h"
+
+int main(int argc, char *argv[])
+{
+  xp_disk_t buf;
+  int fd;
+
+  if (argc != 5) {
+    fprintf(stderr, "Usage: xi_physdev_revoke <domain> <device> <start sector> <n_sectors>\n");
+    return 1;
+  }
+
+  buf.domain = atol(argv[1]);
+  buf.device = atol(argv[2]);
+  buf.start_sect = atol(argv[3]);
+  buf.n_sectors = atol(argv[4]);
+
+  fd = open("/proc/xeno/dom0/phd", O_WRONLY);
+  if (fd < 0) {
+    fprintf(stderr, "Can\'t open /proc/xeno/dom0/phd: %s.\n", strerror(errno));
+    return 1;
+  }
+
+  write(fd, &buf, sizeof(buf));
+  close(fd);
+
+  return 0;
+}
index b9804c6ebc4b6d4c69921b69940b9fd1765b1a1b..00edab32feebc5210c0a337d8f84908a29e7ea7c 100644 (file)
@@ -52,6 +52,7 @@ struct task_struct *do_newdomain(unsigned int dom_id, unsigned int cpu)
 
     spin_lock_init(&p->blk_ring_lock);
     spin_lock_init(&p->page_lock);
+    spin_lock_init(&p->physdev_lock);
 
     p->shared_info = (void *)get_free_page(GFP_KERNEL);
     memset(p->shared_info, 0, PAGE_SIZE);
@@ -62,6 +63,8 @@ struct task_struct *do_newdomain(unsigned int dom_id, unsigned int cpu)
 
     init_blkdev_info(p);
 
+    INIT_LIST_HEAD(&p->physdisk_aces);
+
     SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES);
     SET_GDT_ADDRESS(p, DEFAULT_GDT_ADDRESS);
 
@@ -303,6 +306,9 @@ void release_task(struct task_struct *p)
      */
     destroy_blkdev_info(p);
 
+    /* Free up the physdisk access control info */
+    destroy_physdisk_aces(p);
+
     /* Free all memory associated with this domain. */
     free_page((unsigned long)p->mm.perdomain_pt);
     UNSHARE_PFN(virt_to_page(p->shared_info));
index 07738f98bf1df317b40ac9b894ca8fe8d29c4b0c..809dd6a701277a55bb191eb01c03ac5ba5b172e2 100644 (file)
@@ -104,6 +104,9 @@ static void dispatch_probe_seg(struct task_struct *p, int index);
 static void dispatch_debug_block_io(struct task_struct *p, int index);
 static void dispatch_create_segment(struct task_struct *p, int index);
 static void dispatch_delete_segment(struct task_struct *p, int index);
+static void dispatch_grant_physdev(struct task_struct *p, int index);
+static void dispatch_revoke_physdev(struct task_struct *p, int index);
+static void dispatch_probe_physdev(struct task_struct *p, int index);
 static void make_response(struct task_struct *p, unsigned long id, 
                           unsigned short op, unsigned long st);
 
@@ -396,6 +399,18 @@ static int do_block_io_op_domain(struct task_struct *p, int max_to_do)
            dispatch_delete_segment(p, i);
            break;
 
+       case XEN_BLOCK_PHYSDEV_GRANT:
+           dispatch_grant_physdev(p, i);
+           break;
+
+       case XEN_BLOCK_PHYSDEV_REVOKE:
+           dispatch_revoke_physdev(p, i);
+           break;
+
+       case XEN_BLOCK_PHYSDEV_PROBE:
+           dispatch_probe_physdev(p, i);
+           break;
+
        default:
             DPRINTK("error: unknown block io operation [%d]\n",
                     blk_ring->ring[i].req.operation);
@@ -414,6 +429,115 @@ static void dispatch_debug_block_io(struct task_struct *p, int index)
     DPRINTK("dispatch_debug_block_io: unimplemented\n"); 
 }
 
+static void dispatch_probe_physdev(struct task_struct *p, int index)
+{
+    blk_ring_t *blk_ring = p->blk_ring_base;
+    unsigned long flags, buffer;
+    physdisk_probebuf_t *buf;
+    int result;
+
+    if ( p->domain != 0 )
+    {
+        result = 1;
+        goto out;
+    }
+
+    buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF;
+
+    spin_lock_irqsave(&p->page_lock, flags);
+    if ( !__buffer_is_valid(p, buffer, sizeof(*buf), 1) )
+    {
+        spin_unlock_irqrestore(&p->page_lock, flags);
+        result = 1;
+        goto out;
+    }
+    __lock_buffer(buffer, sizeof(*buf), 1);
+    spin_unlock_irqrestore(&p->page_lock, flags);
+
+    buf = phys_to_virt(buffer);
+    result = xen_physdisk_probe(buf);
+
+    unlock_buffer(p, buffer, sizeof(*buf), 1);
+
+ out:
+    make_response(p, blk_ring->ring[index].req.id, 
+                  XEN_BLOCK_PHYSDEV_PROBE, result); 
+}
+
+static void dispatch_grant_physdev(struct task_struct *p, int index)
+{
+    blk_ring_t *blk_ring = p->blk_ring_base;
+    unsigned long flags, buffer;
+    xp_disk_t *xpd;
+    int result;
+
+    if ( p->domain != 0 )
+    {
+        DPRINTK("dispatch_grant_physdev called by dom%d\n", p->domain);
+        result = 1;
+        goto out;
+    }
+
+    buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF;
+
+    spin_lock_irqsave(&p->page_lock, flags);
+    if ( !__buffer_is_valid(p, buffer, sizeof(xv_disk_t), 1) )
+    {
+        DPRINTK("Bad buffer in dispatch_grant_physdev\n");
+        spin_unlock_irqrestore(&p->page_lock, flags);
+        result = 1;
+        goto out;
+    }
+    __lock_buffer(buffer, sizeof(xv_disk_t), 1);
+    spin_unlock_irqrestore(&p->page_lock, flags);
+
+    xpd = phys_to_virt(buffer);
+    result = xen_physdisk_grant(xpd);
+
+    unlock_buffer(p, buffer, sizeof(xp_disk_t), 1);
+
+ out:
+    make_response(p, blk_ring->ring[index].req.id, 
+                  XEN_BLOCK_PHYSDEV_GRANT, result); 
+}
+  
+static void dispatch_revoke_physdev(struct task_struct *p, int index)
+{
+    blk_ring_t *blk_ring = p->blk_ring_base;
+    unsigned long flags, buffer;
+    xp_disk_t *xpd;
+    int result;
+
+    if ( p->domain != 0 )
+    {
+        DPRINTK("dispatch_grant_physdev called by dom%d\n", p->domain);
+        result = 1;
+        goto out;
+    }
+
+    buffer = blk_ring->ring[index].req.buffer_and_sects[0] & ~0x1FF;
+
+    spin_lock_irqsave(&p->page_lock, flags);
+    if ( !__buffer_is_valid(p, buffer, sizeof(xv_disk_t), 1) )
+    {
+        DPRINTK("Bad buffer in dispatch_grant_physdev\n");
+        spin_unlock_irqrestore(&p->page_lock, flags);
+        result = 1;
+        goto out;
+    }
+    __lock_buffer(buffer, sizeof(xv_disk_t), 1);
+    spin_unlock_irqrestore(&p->page_lock, flags);
+
+    xpd = phys_to_virt(buffer);
+    result = xen_physdisk_revoke(xpd);
+
+    unlock_buffer(p, buffer, sizeof(xp_disk_t), 1);
+
+ out:
+    make_response(p, blk_ring->ring[index].req.id, 
+                  XEN_BLOCK_PHYSDEV_REVOKE, result); 
+}
+
 static void dispatch_create_segment(struct task_struct *p, int index)
 {
     blk_ring_t *blk_ring = p->blk_ring_base;
@@ -593,6 +717,12 @@ static void dispatch_rw_block_io(struct task_struct *p, int index)
                DPRINTK("bad device\n");
                goto bad_descriptor;
            }
+           if (p->domain != 0 &&
+               !xen_physdisk_access_okay(&phys_seg, p, operation)) {
+             DPRINTK("access denied\n");
+             /* XXX not quite right, but close enough. */
+             goto bad_descriptor;
+           }
             new_segs = 1;
         }
         
diff --git a/xen/drivers/block/xen_physdisk.c b/xen/drivers/block/xen_physdisk.c
new file mode 100644 (file)
index 0000000..def17c5
--- /dev/null
@@ -0,0 +1,301 @@
+#include <xeno/sched.h>
+#include <xeno/list.h>
+#include <xeno/blkdev.h>
+#include <xeno/sched.h>
+#include <xeno/slab.h>
+#include <asm/domain_page.h>
+#include <asm/io.h>
+#include <xeno/segment.h>
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#if 0
+#define DPRINTK printk
+#else
+#define DPRINTK(...)
+#endif
+
+/* The idea is that, for each sector of each disk, each domain has two
+   bits, saying whether they can read the sector or write it.  That
+   would take too much memory, so instead each process has a list of
+   (device, start, end, mode) quads which say what it has access to,
+   and we fake the logical view on top of that. */
+struct physdisk_ace {
+  struct list_head list;
+
+  unsigned short device;
+  unsigned long start_sect;
+  unsigned long n_sectors;
+#define PHYSDISK_MODE_R 1
+#define PHYSDISK_MODE_W 2
+  int mode;
+};
+
+/* Operation is a blkdev constant i.e. READ, WRITE, ... */
+/* Must be called with p->physdev_lock held. */
+static struct physdisk_ace *find_ace(const struct task_struct *p,
+                                    unsigned short dev,
+                                    unsigned long sect,
+                                    int operation)
+{
+  struct list_head *cur_ace_head;
+  struct physdisk_ace *cur_ace;
+
+  list_for_each(cur_ace_head, &p->physdisk_aces) {
+    cur_ace = list_entry(cur_ace_head, struct physdisk_ace,
+                        list);
+    DPRINTK("Is [%lx, %lx) good for %lx?\n",
+           cur_ace->start_sect, cur_ace->start_sect + cur_ace->n_sectors,
+           sect);
+    if (sect >= cur_ace->start_sect &&
+       sect < cur_ace->start_sect + cur_ace->n_sectors &&
+       dev == cur_ace->device &&
+       ((operation == READ && (cur_ace->mode & PHYSDISK_MODE_R)) ||
+        (operation == WRITE && (cur_ace->mode & PHYSDISK_MODE_W)))) {
+      DPRINTK("Yes.\n");
+      return cur_ace;
+    } else {
+      DPRINTK("No.\n");
+    }
+  }
+  return NULL;
+}
+
+/* Hold the lock on entry, it remains held on exit. */
+/* XXX we call kmalloc and kfree with GFP_KERNEL and a spinlock held
+   in here.  That wouldn't be allowed under Linux, but, from reading
+   the source, it seems to be okay under Xen... */
+static void xen_physdisk_revoke_access(unsigned short dev,
+                                      unsigned long start_sect,
+                                      unsigned long n_sectors,
+                                      struct task_struct *p)
+{
+  /* Find every ace which intersects [start_sect, start_sect +
+     n_sectors] and either remove it completely or truncate it
+     down. */
+  struct list_head *cur_ace_head;
+  struct physdisk_ace *cur_ace, *new_ace;
+  unsigned long kill_zone_end, ace_end;
+
+  kill_zone_end = start_sect + n_sectors;
+  list_for_each(cur_ace_head, &p->physdisk_aces) {
+    cur_ace = list_entry(cur_ace_head, struct physdisk_ace,
+                        list);
+    ace_end = cur_ace->start_sect + cur_ace->n_sectors;
+    if (cur_ace->start_sect > kill_zone_end ||
+       ace_end < start_sect)
+      continue;
+    
+    if (cur_ace->start_sect >= start_sect &&
+       ace_end < kill_zone_end) {
+      /* ace entirely within kill zone -> kill it */
+      list_del(cur_ace_head);
+      cur_ace_head = cur_ace_head->next;
+      kfree(cur_ace);
+    } else if (ace_end < kill_zone_end) {
+      /* ace start before kill start, ace end in kill zone, 
+        move ace end. */
+      cur_ace->n_sectors = start_sect - cur_ace->start_sect;
+    } else if (cur_ace->start_sect >= start_sect) {
+      /* ace start after kill start, ace end outside kill zone,
+        move ace start. */
+      cur_ace->start_sect = kill_zone_end;
+      cur_ace->n_sectors = ace_end - cur_ace->start_sect;
+    } else {
+      /* The fun one: the kill zone entirely includes the ace. */
+      /* Cut the current ace down to just the bit before the kzone,
+        create a new ace for the bit just after it. */
+      new_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL);
+      new_ace->device = dev;
+      new_ace->start_sect = kill_zone_end;
+      new_ace->n_sectors = ace_end - kill_zone_end;
+      new_ace->mode = cur_ace->mode;
+
+      cur_ace->n_sectors = start_sect - cur_ace->start_sect;
+
+      list_add(&new_ace->list, cur_ace_head);
+      cur_ace_head = new_ace->list.next;
+    }
+  }
+}
+
+/* Hold the lock on entry, it remains held on exit. */
+static int xen_physdisk_grant_access(unsigned short dev,
+                                    unsigned long start_sect,
+                                    unsigned long n_sectors,
+                                    int mode,
+                                    struct task_struct *p)
+{
+  struct physdisk_ace *cur_ace;
+
+  /* Make sure it won't overlap with any existing ACEs. */
+  /* XXX this isn't quite right if the domain already has read access
+     and we try to grant write access, or vice versa. */
+  xen_physdisk_revoke_access(dev, start_sect, n_sectors, p);
+  
+  cur_ace = kmalloc(sizeof(*cur_ace), GFP_KERNEL);
+  cur_ace->device = dev;
+  cur_ace->start_sect = start_sect;
+  cur_ace->n_sectors = n_sectors;
+  cur_ace->mode = mode;
+
+  list_add_tail(&cur_ace->list, &p->physdisk_aces);
+
+  return 0;
+}
+
+static void xen_physdisk_probe_access(physdisk_probebuf_t *buf,
+                                     struct task_struct *p)
+{
+  int max_aces;
+  int n_aces;
+  struct list_head *cur_ace_head;
+  struct physdisk_ace *cur_ace;
+  int x;
+
+  max_aces = buf->n_aces;
+  n_aces = 0;
+  list_for_each(cur_ace_head, &p->physdisk_aces) {
+    if (x < buf->start_ind) {
+      x++;
+      continue;
+    }
+    cur_ace = list_entry(cur_ace_head, struct physdisk_ace,
+                        list);
+    buf->entries[n_aces].device = cur_ace->device;
+    buf->entries[n_aces].start_sect = cur_ace->start_sect;
+    buf->entries[n_aces].n_sectors = cur_ace->n_sectors;
+    buf->entries[n_aces].mode = cur_ace->mode;
+    n_aces++;
+    if (n_aces >= max_aces)
+      break;
+  }
+  buf->n_aces = n_aces;
+  printk("Found a total of %x aces (max %x).\n", n_aces, max_aces);
+}
+
+int xen_physdisk_grant(xp_disk_t *xpd_in)
+{
+  struct task_struct *p;
+  xp_disk_t *xpd = map_domain_mem(virt_to_phys(xpd_in));
+  int res;
+
+  p = current;
+  DPRINTK("Have current.\n");
+  DPRINTK("Target domain %x\n", xpd->domain);
+
+  do {
+    p = p->next_task;
+  } while (p != current && p->domain != xpd->domain);
+  if (p->domain != xpd->domain) {
+    DPRINTK("Bad domain! No biscuit!\n");
+    res = 1;
+    goto out;
+  }
+  spin_lock(&p->physdev_lock);
+  res = xen_physdisk_grant_access(xpd->device,
+                                 xpd->start_sect,
+                                 xpd->n_sectors,
+                                 xpd->mode,
+                                 p);
+  spin_unlock(&p->physdev_lock);
+
+ out:
+  unmap_domain_mem(xpd);
+  return res;
+}
+
+int xen_physdisk_revoke(xp_disk_t *xpd_in)
+{
+  struct task_struct *p;
+  xp_disk_t *xpd = map_domain_mem(virt_to_phys(xpd_in));
+  int res;
+
+  p = current;
+
+  do {
+    p = p->next_task;
+  } while (p != current && p->domain != xpd->domain);
+  if (p->domain != xpd->domain) {
+    res = 1;
+    goto out;
+  }
+  spin_lock(&p->physdev_lock);
+  xen_physdisk_revoke_access(xpd->device,
+                            xpd->start_sect,
+                            xpd->n_sectors,
+                            p);
+  spin_unlock(&p->physdev_lock);
+  res = 0;
+ out:
+  unmap_domain_mem(xpd);
+  return res;
+}
+
+int xen_physdisk_probe(physdisk_probebuf_t *buf_in)
+{
+  struct task_struct *p;
+  physdisk_probebuf_t *buf = map_domain_mem(virt_to_phys(buf_in));
+  int res;
+
+  p = current;
+  do {
+    p = p->next_task;
+  } while (p != current && p->domain != buf->domain);
+  if (p->domain != buf->domain) {
+    res = 1;
+    goto out;
+  }
+  printk("initially %x aces.\n", buf->n_aces);
+  spin_lock(&p->physdev_lock);
+  xen_physdisk_probe_access(buf, p);
+  spin_unlock(&p->physdev_lock);
+  printk("%x aces.\n", buf->n_aces);
+  res = 0;
+ out:
+  unmap_domain_mem(buf);
+  return res;
+}
+
+int xen_physdisk_access_okay(phys_seg_t *pseg, struct task_struct *p,
+                            int operation)
+{
+  struct physdisk_ace *cur_ace;
+  unsigned long sect;
+
+  DPRINTK("Checking access for domain %d, start sect %d, length %d.\n",
+         p->domain, pseg->sector_number, pseg->nr_sects);
+
+  for (sect = pseg->sector_number;
+       sect < pseg->sector_number + pseg->nr_sects;
+       ) {
+    /* XXX this would be a lot faster if the aces were sorted on start
+       address.  Also in revoke_access. */
+    spin_lock(&p->physdev_lock);
+    cur_ace = find_ace(p, pseg->dev, sect, operation);
+    spin_unlock(&p->physdev_lock);
+    if (!cur_ace) {
+      /* Default closed. */
+      return 0;
+    }
+    sect += MAX(cur_ace->n_sectors, pseg->nr_sects + pseg->sector_number - sect);
+  }
+  return 1;
+}
+
+void destroy_physdisk_aces(struct task_struct *p)
+{
+  struct list_head *cur_ace_head, *next_head;
+  struct physdisk_ace *cur_ace;
+
+  spin_lock(&p->physdev_lock); /* We never release this again. */
+
+  for (cur_ace_head = p->physdisk_aces.next;
+       cur_ace_head != &p->physdisk_aces;
+       cur_ace_head = next_head) {
+    cur_ace = list_entry(cur_ace_head, struct physdisk_ace,
+                        list);
+    next_head = cur_ace_head->next;
+    kfree(cur_ace);
+  }
+}
index 947f87abe37a25ec9a0b12c20b8692ded8038c89..c60b4ac0e39d7ffb0501fc11ff882af4faee8c21 100644 (file)
 #define XEN_BLOCK_SEG_CREATE   7  /* create segment (vhd) */
 #define XEN_BLOCK_SEG_DELETE   8  /* delete segment (vhd) */
 #define XEN_BLOCK_PROBE_SEG    9  /* get vhd config from hypervisor */
+#define XEN_BLOCK_PHYSDEV_GRANT 10 /* grant access to range of disk blocks */
+#define XEN_BLOCK_PHYSDEV_REVOKE 11 /* revoke access to range of disk blocks */
+#define XEN_BLOCK_PHYSDEV_PROBE 12 /* probe for a domain's physdev
+                                     accesses */
 
 /* NB. Ring size must be small enough for sizeof(blk_ring_t) <= PAGE_SIZE. */
 #define BLK_RING_SIZE        64
@@ -139,4 +143,26 @@ typedef struct xv_disk
   xv_extent_t extents[XEN_MAX_DISK_COUNT];    /* arbitrary reuse of constant */
 } xv_disk_t;
 
+typedef struct xp_disk
+{
+  int mode;
+  int domain;
+  unsigned short device;
+  unsigned long start_sect;
+  unsigned long n_sectors;
+} xp_disk_t;
+
+#define PHYSDISK_MAX_ACES_PER_REQUEST 254
+typedef struct {
+  int n_aces;
+  int domain;
+  int start_ind;
+  struct {
+    unsigned short device;
+    unsigned long start_sect;
+    unsigned long n_sectors;
+    unsigned mode;
+  } entries[PHYSDISK_MAX_ACES_PER_REQUEST];
+} physdisk_probebuf_t;
+
 #endif
index 7d9e2fcbd27208b95f2d5c329fdbd617cc7f28d0..351afa5e8dcbbe484296d64b9dafd7245c813e1a 100644 (file)
@@ -133,6 +133,11 @@ struct task_struct
     unsigned int blk_resp_prod; /* (private version of) response producer */
     struct list_head blkdev_list;
     spinlock_t blk_ring_lock;
+    struct list_head physdisk_aces; /* physdisk_ace structures
+                                      describing what bits of disk
+                                      the process can do raw access
+                                      to. */
+    spinlock_t physdev_lock;
     segment_t *segment_list[XEN_MAX_SEGMENTS];                        /* xvd */
 
     /* VM */
index 6423104172490e2d5889bca4f9b09141cc4ab97a..c6997d271768aa521877ed63b1a9936a83cb00b2 100644 (file)
@@ -1,3 +1,3 @@
 O_TARGET := blk.o
-obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o
+obj-y := xl_block.o xl_ide.o xl_scsi.o xl_segment.o xl_segment_proc.o xl_physdisk_proc.o
 include $(TOPDIR)/Rules.make
index d3e09eb52caf88171934c0023451726d1abd9c1a..b204aa25861c80a7da94874f48c019a6e79470be 100644 (file)
@@ -307,6 +307,9 @@ static int hypervisor_request(unsigned long   id,
     {
     case XEN_BLOCK_SEG_CREATE:
     case XEN_BLOCK_SEG_DELETE:
+    case XEN_BLOCK_PHYSDEV_GRANT:
+    case XEN_BLOCK_PHYSDEV_REVOKE:
+    case XEN_BLOCK_PHYSDEV_PROBE:
     case XEN_BLOCK_PROBE_BLK:
     case XEN_BLOCK_PROBE_SEG:
         if ( RING_FULL ) return 1;
@@ -478,6 +481,9 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
         case XEN_BLOCK_SEG_DELETE:
         case XEN_BLOCK_PROBE_SEG:
         case XEN_BLOCK_PROBE_BLK:
+       case XEN_BLOCK_PHYSDEV_GRANT:
+       case XEN_BLOCK_PHYSDEV_REVOKE:
+       case XEN_BLOCK_PHYSDEV_PROBE:
             if ( bret->status )
                 printk(KERN_ALERT "Bad return from blkdev control request\n");
             xlblk_control_msg_pending = 0;
diff --git a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c
new file mode 100644 (file)
index 0000000..6b4df31
--- /dev/null
@@ -0,0 +1,94 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <asm/errno.h>
+#include <linux/slab.h>
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *phd;
+
+extern int xenolinux_control_msg(int operration, char *buffer, int size);
+
+static ssize_t proc_read_phd(struct file * file, char * buff, size_t size, loff_t * off)
+{
+  physdisk_probebuf_t *buf;
+  int res;
+
+  if (size != sizeof(physdisk_probebuf_t))
+    return -EINVAL;
+
+  buf = kmalloc(sizeof(physdisk_probebuf_t), GFP_KERNEL);
+  if (!buf)
+    return -ENOMEM;
+
+  if (copy_from_user(buf, buff, size)) {
+    kfree(buf);
+    return -EFAULT;
+  }
+
+  printk("max aces 1 %x\n", buf->n_aces);
+
+  res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_PROBE, (void *)buf,
+                             sizeof(physdisk_probebuf_t));
+
+  printk("max aces %x\n", buf->n_aces);
+
+  if (res)
+    res = -EINVAL;
+  else {
+    res = sizeof(physdisk_probebuf_t);
+    if (copy_to_user(buff, buf, sizeof(physdisk_probebuf_t))) {
+      res = -EFAULT;
+    }
+  }
+  kfree(buf);
+  return res;
+}
+
+static int proc_write_phd(struct file *file, const char *buffer,
+                         size_t count, loff_t *ignore)
+{
+  char *local;
+  int res;
+
+  if (count != sizeof(xp_disk_t))
+    return -EINVAL;
+
+  local = kmalloc(count + 1, GFP_KERNEL);
+  if (!local)
+    return -ENOMEM;
+  if (copy_from_user(local, buffer, count)) {
+    res = -EFAULT;
+    goto out;
+  }
+  local[count] = 0;
+
+  res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_GRANT, local, count);
+  if (res == 0)
+    res = count;
+  else
+    res = -EINVAL;
+ out:
+  kfree(local);
+  return res;
+}
+
+static struct file_operations proc_phd_fops = {
+  read : proc_read_phd,
+  write : proc_write_phd
+};
+
+int __init xlphysdisk_proc_init(void)
+{
+  phd = create_proc_entry("xeno/dom0/phd", 0644, NULL);
+  if (!phd) {
+    panic("Can\'t create phd proc entry!\n");
+  }
+  phd->data = NULL;
+  phd->proc_fops = &proc_phd_fops;
+  phd->owner = THIS_MODULE;
+
+  return 0;
+}
diff --git a/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~ b/xenolinux-2.4.21-sparse/arch/xeno/drivers/block/xl_physdisk_proc.c~
new file mode 100644 (file)
index 0000000..6c76bd5
--- /dev/null
@@ -0,0 +1,94 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <asm/errno.h>
+#include <linux/slab.h>
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *phd;
+
+extern int xenolinux_control_msg(int operration, char *buffer, int size);
+
+static ssize_t proc_read_phd(struct file * file, char * buff, size_t size, loff_t * off)
+{
+  physdisk_probebuf_t *buf;
+  int res;
+
+  if (size != sizeof(physdisk_probebuf_t))
+    return -EINVAL;
+
+  buf = kmalloc(sizeof(physdisk_probebuf_t), GFP_KERNEL);
+  if (!buf)
+    return -ENOMEM;
+
+  if (copy_from_user(buf, buff, size)) {
+    kfree(buf);
+    return -EFAULT;
+  }
+
+  printk("max aces %x\n", buf->n_aces);
+
+  res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_PROBE, (void *)buf,
+                             sizeof(physdisk_probebuf_t));
+
+  printk("max aces %x\n", buf->n_aces);
+
+  if (res)
+    res = -EINVAL;
+  else {
+    res = sizeof(physdisk_probebuf_t);
+    if (copy_to_user(buff, buf, sizeof(physdisk_probebuf_t))) {
+      res = -EFAULT;
+    }
+  }
+  kfree(buf);
+  return res;
+}
+
+static int proc_write_phd(struct file *file, const char *buffer,
+                         size_t count, loff_t *ignore)
+{
+  char *local;
+  int res;
+
+  if (count != sizeof(xp_disk_t))
+    return -EINVAL;
+
+  local = kmalloc(count + 1, GFP_KERNEL);
+  if (!local)
+    return -ENOMEM;
+  if (copy_from_user(local, buffer, count)) {
+    res = -EFAULT;
+    goto out;
+  }
+  local[count] = 0;
+
+  res = xenolinux_control_msg(XEN_BLOCK_PHYSDEV_GRANT, local, count);
+  if (res == 0)
+    res = count;
+  else
+    res = -EINVAL;
+ out:
+  kfree(local);
+  return res;
+}
+
+static struct file_operations proc_phd_fops = {
+  read : proc_read_phd,
+  write : proc_write_phd
+};
+
+int __init xlphysdisk_proc_init(void)
+{
+  phd = create_proc_entry("xeno/dom0/phd", 0644, NULL);
+  if (!phd) {
+    panic("Can\'t create phd proc entry!\n");
+  }
+  phd->data = NULL;
+  phd->proc_fops = &proc_phd_fops;
+  phd->owner = THIS_MODULE;
+
+  return 0;
+}
index 411b6def8b88f294e45e5355cf1ca95d539980f9..60f5584e2f1a17b4f5e1a63cfdcd344e1ae006ca 100644 (file)
@@ -1505,6 +1505,7 @@ int __init blk_dev_init(void)
     xlblk_init();
     xlseg_init();
     xlseg_proc_init();
+    xlphysdisk_proc_init();
 #endif
 
        return 0;